import org.junit.Test;
import static org.junit.Assert.*;

public class ExerciseTest {
    
    // 测试构造方法和基本功能
    @Test
    public void testExercise() {
        Exercise exercise = new Exercise();
        assertEquals("初始大小错误", 0, exercise.size());
        
        // 添加算式测试
        BinaryOperation op1 = new BinaryOperation(10, 5, '+');
        BinaryOperation op2 = new BinaryOperation(20, 8, '-');
        exercise.add(op1);
        exercise.add(op2);
        
        assertEquals("添加后大小错误", 2, exercise.size());
        assertEquals("第一个算式错误", op1, exercise.get(0));
        assertEquals("第二个算式错误", op2, exercise.get(1));
    }
    
    // 测试contains方法
    @Test
    public void testContains() {
        Exercise exercise = new Exercise();
        BinaryOperation op1 = new BinaryOperation(10, 5, '+');
        BinaryOperation op2 = new BinaryOperation(20, 8, '-');
        BinaryOperation op3 = new BinaryOperation(10, 5, '+'); // 与op1相同
        BinaryOperation op4 = new BinaryOperation(15, 3, '+'); // 不同的算式
        
        exercise.add(op1);
        exercise.add(op2);
        
        assertTrue("应该包含op1", exercise.contains(op1));
        assertTrue("应该包含op3（与op1相同）", exercise.contains(op3));
        assertFalse("不应该包含op4", exercise.contains(op4));
        assertFalse("空习题集不应该包含任何算式", new Exercise().contains(op1));
    }
    
    // 测试generateAdditionExercise方法
    @Test
    public void testGenerateAdditionExercise() {
        Exercise exercise = new Exercise();
        int count = 10;
        exercise.generateAdditionExercise(count);
        
        assertEquals("生成的题目数量错误", count, exercise.size());
        
        // 验证所有都是加法且无重复
        boolean allAddition = true;
        boolean hasDuplicates = false;
        
        for (int i = 0; i < exercise.size() && allAddition; i++) {
            BinaryOperation op1 = exercise.get(i);
            if (op1.getOperator() != '+') {
                allAddition = false;
                break;
            }
            
            for (int j = i + 1; j < exercise.size() && !hasDuplicates; j++) {
                BinaryOperation op2 = exercise.get(j);
                if (op1.equals(op2)) {
                    hasDuplicates = true;
                    break;
                }
            }
        }
        
        assertTrue("所有题目应该是加法", allAddition);
        assertFalse("不应该有重复题目", hasDuplicates);
    }
    
    // 测试generateSubtractExercise方法
    @Test
    public void testGenerateSubtractExercise() {
        Exercise exercise = new Exercise();
        int count = 10;
        exercise.generateSubtractExercise(count);
        
        assertEquals("生成的题目数量错误", count, exercise.size());
        
        // 验证所有都是减法且结果非负且无重复
        boolean allSubtract = true;
        boolean allNonNegative = true;
        boolean hasDuplicates = false;
        
        for (int i = 0; i < exercise.size() && allSubtract && allNonNegative; i++) {
            BinaryOperation op1 = exercise.get(i);
            if (op1.getOperator() != '-') {
                allSubtract = false;
                break;
            }
            if (op1.getValue() < 0) {
                allNonNegative = false;
                break;
            }
            
            for (int j = i + 1; j < exercise.size() && !hasDuplicates; j++) {
                BinaryOperation op2 = exercise.get(j);
                if (op1.equals(op2)) {
                    hasDuplicates = true;
                    break;
                }
            }
        }
        
        assertTrue("所有题目应该是减法", allSubtract);
        assertTrue("所有结果应该非负", allNonNegative);
        assertFalse("不应该有重复题目", hasDuplicates);
    }
    
    // 测试generateBinaryExercise方法
    @Test
    public void testGenerateBinaryExercise() {
        Exercise exercise = new Exercise();
        int count = 10;
        exercise.generateBinaryExercise(count);
        
        assertEquals("生成的题目数量错误", count, exercise.size());
        
        // 统计加减法数量
        int addCount = 0;
        int subCount = 0;
        boolean hasDuplicates = false;
        
        for (int i = 0; i < exercise.size() && !hasDuplicates; i++) {
            BinaryOperation op1 = exercise.get(i);
            if (op1.getOperator() == '+') {
                addCount++;
            } else if (op1.getOperator() == '-') {
                subCount++;
            }
            
            // 检查重复
            for (int j = i + 1; j < exercise.size() && !hasDuplicates; j++) {
                BinaryOperation op2 = exercise.get(j);
                if (op1.equals(op2)) {
                    hasDuplicates = true;
                    break;
                }
            }
        }
        
        assertTrue("应该包含加法题目", addCount > 0);
        assertTrue("应该包含减法题目", subCount > 0);
        assertEquals("加法和减法题目总数应该等于题目总数", count, addCount + subCount);
        assertFalse("不应该有重复题目", hasDuplicates);
        
        // 测试奇数数量的情况
        Exercise oddExercise = new Exercise();
        oddExercise.generateBinaryExercise(5);
        int oddAdd = 0;
        int oddSub = 0;
        for (BinaryOperation op : oddExercise) {
            if (op.getOperator() == '+') oddAdd++;
            else if (op.getOperator() == '-') oddSub++;
        }
        assertEquals("奇数数量的题目总数错误", 5, oddAdd + oddSub);
        assertEquals("奇数数量的加法题目应该是总数的一半向下取整", 2, oddAdd);
        assertEquals("奇数数量的减法题目应该是总数减去加法题目数", 3, oddSub);
    }
    
    // 测试formatAndDisplay方法（这里我们只测试功能调用不会抛出异常）
    @Test
    public void testFormatAndDisplay() {
        Exercise exercise = new Exercise();
        // 添加一些算式以便测试显示
        exercise.add(new BinaryOperation(1, 2, '+'));
        exercise.add(new BinaryOperation(3, 4, '-'));
        
        // 测试默认列数（5列）
        try {
            exercise.formatAndDisplay();
            // 如果没有抛出异常，则测试通过
            assertTrue(true);
        } catch (Exception e) {
            fail("formatAndDisplay方法抛出异常: " + e.getMessage());
        }
        
        // 测试指定列数
        try {
            exercise.formatAndDisplay(2);
            exercise.formatAndDisplay(1);
            // 如果没有抛出异常，则测试通过
            assertTrue(true);
        } catch (Exception e) {
            fail("formatAndDisplay方法抛出异常: " + e.getMessage());
        }
    }
}